﻿#include "epoll_watch.h"
#include "base_type.h"
#include "as_poller.h"
#include "as_channel.h"
#include "thread_name.h"
#include <iostream>
#include <vector>
#include <functional>
#ifdef _WIN32
#else
#include <sys/epoll.h>
#endif

as::net::EpollWatch::EpollWatch()
{
	epoll_fd_ = epoll_create1(0);
	thread_id_ = std::this_thread::get_id();
	as::thread::SetThreadName(thread_id_, "epoll-watch");
	poller_ = std::make_shared<as::net::Poller>(this);
}

as::net::EpollWatch::~EpollWatch()
{
#ifdef _WIN32
	epoll_close(epoll_fd_);
#else
	close(epoll_fd_);
#endif
	LOG_DEBUG << "delete epoll watch";
}


void as::net::EpollWatch::UpdateChannel(Channel* channel)
{
	poller_->UpdateChannel(channel);
}

void as::net::EpollWatch::RemoveChannel(Channel* channel)
{
	poller_->RemoveChannel(channel);
}

void as::net::EpollWatch::WatchLoop()
{
	isExit = false;
	Loop();
}

void as::net::EpollWatch::Loop()
{
	std::vector<Channel*> channelVec;
	TimeValue tv;
	while (isExit == false)
	{
		channelVec.clear();
		//这里因为不等待的,所以会一直执行
		poller_->pool(channelVec);
		for (auto channel : channelVec)
		{
			channel->HandleEvent(tv);
		}

		//run timer fun
		ExceutePending(tv);
		tv.SetMsTime(TimeValue::GetMsTime());
	}

	ExceutePending(tv, true);
}

void as::net::EpollWatch::ExceutePending(const TimeValue &tv, bool isExit)
{
	loop_lock_.lock();
	if (pend_fun_.size() <= 0)
	{
		loop_lock_.unlock();
		return;
	}

	std::vector<EpTimer> funs;
	funs.swap(pend_fun_);
	loop_lock_.unlock();

	std::vector<EpTimer> tmp;
	for (auto& timer : funs)
	{
		if (timer.t_ == 0 || tv > timer.t_)
		{
			if (timer.loop_-- > 0)
				timer.fun_();
			if (timer.loop_ > 0)
			{
				if (timer.interval > 0)
				{
					timer.t_ = tv.GetMsTime() + timer.interval;
				}
				tmp.emplace_back(timer);
			}
		}
		else
		{
			tmp.emplace_back(timer);
		}
	}

	if (isExit == false)
	{
		loop_lock_.lock();
		for (auto& it : tmp)
		{
			pend_fun_.emplace_back(it);
		}
		loop_lock_.unlock();
	}
}

void as::net::EpollWatch::AddTimer(TimerFun fun, int delay, int loop)
{
	std::lock_guard<std::mutex> l(loop_lock_);
	EpTimer t;
	t.fun_ = fun;
	t.t_ = TimeValue::GetMsTime() + delay;
	t.interval = delay;
	t.loop_ = loop;
	pend_fun_.emplace_back(t);
}

void as::net::EpollWatch::IsRunInLoop(TimerFun fun)
{
	if (IsLoopThread())
	{
		fun();
	}
	else
	{
		AddTimer(std::move(fun));
	}
}

bool as::net::EpollWatch::IsLoopThread()
{
	return std::this_thread::get_id() == thread_id_;
}

void as::net::EpollWatch::Exit()
{
	isExit = true;
}

int as::net::EpollWatch::GenerateConnId()
{
	conn_id_ = (conn_id_ + 1) % 10000000;
	return conn_id_;
}
